home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / binutils.7 / binutils / binutils-2.7 / gprof / gmon_io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-04  |  10.0 KB  |  415 lines

  1. /*
  2.  * Input and output from/to gmon.out files.
  3.  */
  4. #include "cg_arcs.h"
  5. #include "basic_blocks.h"
  6. #include "bfd.h"
  7. #include "core.h"
  8. #include "call_graph.h"
  9. #include "gmon_io.h"
  10. #include "gmon_out.h"
  11. #include "gmon.h"        /* fetch header for old format */
  12. #include "gprof.h"
  13. #include "hertz.h"
  14. #include "hist.h"
  15. #include "libiberty.h"
  16.  
  17. int gmon_input = 0;
  18. int gmon_file_version = 0;    /* 0 == old (non-versioned) file format */
  19.  
  20. /*
  21.  * This probably ought to be in libbfd.
  22.  */
  23. bfd_vma
  24. DEFUN (get_vma, (abfd, addr), bfd * abfd AND bfd_byte * addr)
  25. {
  26.   switch (sizeof (char*))
  27.     {
  28.     case 4:
  29.       return bfd_get_32 (abfd, addr);
  30.     case 8:
  31.       return bfd_get_64 (abfd, addr);
  32.     default:
  33.       fprintf (stderr, "%s: bfd_vma has unexpected size of %ld bytes\n",
  34.            whoami, (long) sizeof (char*));
  35.       done (1);
  36.     }
  37. }
  38.  
  39.  
  40. /*
  41.  * This probably ought to be in libbfd.
  42.  */
  43. void
  44. DEFUN (put_vma, (abfd, val, addr), bfd * abfd AND bfd_vma val AND bfd_byte * addr)
  45. {
  46.   switch (sizeof (char*))
  47.     {
  48.     case 4:
  49.       bfd_put_32 (abfd, val, addr);
  50.       break;
  51.     case 8:
  52.       bfd_put_64 (abfd, val, addr);
  53.       break;
  54.     default:
  55.       fprintf (stderr, "%s: bfd_vma has unexpected size of %ld bytes\n",
  56.            whoami, (long) sizeof (char*));
  57.       done (1);
  58.     }
  59. }
  60.  
  61.  
  62. void
  63. DEFUN (gmon_out_read, (filename), const char *filename)
  64. {
  65.   FILE *ifp;
  66.   struct gmon_hdr ghdr;
  67.   unsigned char tag;
  68.   int nhist = 0, narcs = 0, nbbs = 0;
  69.  
  70.   /* open gmon.out file: */
  71.  
  72.   if (strcmp (filename, "-") == 0)
  73.     {
  74.       ifp = stdin;
  75.     }
  76.   else
  77.     {
  78.       ifp = fopen (filename, FOPEN_RB);
  79.       if (!ifp)
  80.     {
  81.       perror (filename);
  82.       done (1);
  83.     }
  84.     }
  85.   if (fread (&ghdr, sizeof (struct gmon_hdr), 1, ifp) != 1)
  86.     {
  87.       fprintf (stderr, "%s: file too short to be a gmon file\n",
  88.            filename);
  89.       done (1);
  90.     }
  91.  
  92.   if ((file_format == FF_MAGIC) ||
  93.       (file_format == FF_AUTO && !strncmp (&ghdr.cookie[0], GMON_MAGIC, 4)))
  94.     {
  95.       if (file_format == FF_MAGIC && strncmp (&ghdr.cookie[0], GMON_MAGIC, 4))
  96.     {
  97.       fprintf (stderr, "%s: file `%s' has bad magic cookie\n",
  98.            whoami, filename);
  99.       done (1);
  100.     }
  101.  
  102.       /* right magic, so it's probably really a new gmon.out file */
  103.  
  104.       gmon_file_version = bfd_get_32 (core_bfd, (bfd_byte *) ghdr.version);
  105.       if (gmon_file_version != GMON_VERSION && gmon_file_version != 0)
  106.     {
  107.       fprintf (stderr,
  108.            "%s: file `%s' has unsupported version %d\n",
  109.            whoami, filename, gmon_file_version);
  110.       done (1);
  111.     }
  112.  
  113.       /* read in all the records: */
  114.       while (fread (&tag, sizeof (tag), 1, ifp) == 1)
  115.     {
  116.       switch (tag)
  117.         {
  118.         case GMON_TAG_TIME_HIST:
  119.           ++nhist;
  120.           gmon_input |= INPUT_HISTOGRAM;
  121.           hist_read_rec (ifp, filename);
  122.           break;
  123.  
  124.         case GMON_TAG_CG_ARC:
  125.           ++narcs;
  126.           gmon_input |= INPUT_CALL_GRAPH;
  127.           cg_read_rec (ifp, filename);
  128.           break;
  129.  
  130.         case GMON_TAG_BB_COUNT:
  131.           ++nbbs;
  132.           gmon_input |= INPUT_BB_COUNTS;
  133.           bb_read_rec (ifp, filename);
  134.           break;
  135.  
  136.         default:
  137.           fprintf (stderr,
  138.                "%s: %s: found bad tag %d (file corrupted?)\n",
  139.                whoami, filename, tag);
  140.           done (1);
  141.         }
  142.     }
  143.     }
  144.   else if (file_format == FF_AUTO || file_format == FF_BSD)
  145.     {
  146.       struct hdr
  147.       {
  148.     bfd_vma low_pc;
  149.     bfd_vma high_pc;
  150.     int ncnt;
  151.       };
  152.       int i, samp_bytes, count;
  153.       bfd_vma from_pc, self_pc;
  154.       struct raw_arc raw_arc;
  155.       struct raw_phdr raw;
  156.       static struct hdr h;
  157.       UNIT raw_bin_count;
  158.       struct hdr tmp;
  159.  
  160.       /*
  161.        * Information from a gmon.out file is in two parts: an array of
  162.        * sampling hits within pc ranges, and the arcs.
  163.        */
  164.       gmon_input = INPUT_HISTOGRAM | INPUT_CALL_GRAPH;
  165.  
  166.       /*
  167.        * This fseek() ought to work even on stdin as long as it's
  168.        * not an interactive device (heck, is there anybody who would
  169.        * want to type in a gmon.out at the terminal?).
  170.        */
  171.       if (fseek (ifp, 0, SEEK_SET) < 0)
  172.     {
  173.       perror (filename);
  174.       done (1);
  175.     }
  176.       if (fread (&raw, 1, sizeof (struct raw_phdr), ifp)
  177.       != sizeof (struct raw_phdr))
  178.     {
  179.       fprintf (stderr, "%s: file too short to be a gmon file\n",
  180.            filename);
  181.       done (1);
  182.     }
  183.       tmp.low_pc = get_vma (core_bfd, (bfd_byte *) &raw.low_pc[0]);
  184.       tmp.high_pc = get_vma (core_bfd, (bfd_byte *) &raw.high_pc[0]);
  185.       tmp.ncnt = bfd_get_32 (core_bfd, (bfd_byte *) &raw.ncnt[0]);
  186.  
  187. #ifdef BSD44_FORMAT
  188.       {
  189.     int profrate;
  190.  
  191.     profrate = bfd_get_32 (core_bfd, (bfd_byte *) &raw.version[0]);
  192.     if (!s_highpc)
  193.       hz = profrate;
  194.     else if (hz != profrate)
  195.       {
  196.         fprintf (stderr,
  197.              "%s: profiling rate incompatible with first gmon file\n",
  198.              filename);
  199.         done (1);
  200.       }
  201.       }
  202. #endif
  203.  
  204.       if (s_highpc && (tmp.low_pc != h.low_pc ||
  205.                tmp.high_pc != h.high_pc || tmp.ncnt != h.ncnt))
  206.     {
  207.       fprintf (stderr, "%s: incompatible with first gmon file\n",
  208.            filename);
  209.       done (1);
  210.     }
  211.       h = tmp;
  212.       s_lowpc = (bfd_vma) h.low_pc;
  213.       s_highpc = (bfd_vma) h.high_pc;
  214.       lowpc = (bfd_vma) h.low_pc / sizeof (UNIT);
  215.       highpc = (bfd_vma) h.high_pc / sizeof (UNIT);
  216.       samp_bytes = h.ncnt - sizeof (struct raw_phdr);
  217.       hist_num_bins = samp_bytes / sizeof (UNIT);
  218.       DBG (SAMPLEDEBUG,
  219.        printf ("[gmon_out_read] lowpc 0x%lx highpc 0x%lx ncnt %d\n",
  220.            h.low_pc, h.high_pc, h.ncnt);
  221.        printf ("[gmon_out_read]   s_lowpc 0x%lx   s_highpc 0x%lx\n",
  222.            s_lowpc, s_highpc);
  223.        printf ("[gmon_out_read]     lowpc 0x%lx     highpc 0x%lx\n",
  224.            lowpc, highpc);
  225.        printf ("[gmon_out_read] samp_bytes %d hist_num_bins %d\n",
  226.            samp_bytes, hist_num_bins));
  227.  
  228.       if (hist_num_bins)
  229.     {
  230.       ++nhist;
  231.     }
  232.  
  233.       if (!hist_sample)
  234.     {
  235.       hist_sample =
  236.         (int *) xmalloc (hist_num_bins * sizeof (hist_sample[0]));
  237.       memset (hist_sample, 0, hist_num_bins * sizeof (hist_sample[0]));
  238.     }
  239.  
  240.       for (i = 0; i < hist_num_bins; ++i)
  241.     {
  242.       if (fread (raw_bin_count, sizeof (raw_bin_count), 1, ifp) != 1)
  243.         {
  244.           fprintf (stderr,
  245.                "%s: unexpected EOF after reading %d/%d bins\n",
  246.                whoami, --i, hist_num_bins);
  247.           done (1);
  248.         }
  249.       hist_sample[i] += bfd_get_16 (core_bfd, (bfd_byte *) raw_bin_count);
  250.     }
  251.  
  252.       /*
  253.        * The rest of the file consists of a bunch of <from,self,count>
  254.        * tuples:
  255.        */
  256.       while (fread (&raw_arc, sizeof (raw_arc), 1, ifp) == 1)
  257.     {
  258.       ++narcs;
  259.       from_pc = get_vma (core_bfd, (bfd_byte *) raw_arc.from_pc);
  260.       self_pc = get_vma (core_bfd, (bfd_byte *) raw_arc.self_pc);
  261.       count = bfd_get_32 (core_bfd, (bfd_byte *) raw_arc.count);
  262.       DBG (SAMPLEDEBUG,
  263.          printf ("[gmon_out_read] frompc 0x%lx selfpc 0x%lx count %d\n",
  264.              from_pc, self_pc, count));
  265.       /* add this arc: */
  266.       cg_tally (from_pc, self_pc, count);
  267.     }
  268.       fclose (ifp);
  269.  
  270.       if (hz == HZ_WRONG)
  271.     {
  272.       /*
  273.        * How many ticks per second?  If we can't tell, report
  274.        * time in ticks.
  275.        */
  276.       hz = hertz ();
  277.       if (hz == HZ_WRONG)
  278.         {
  279.           hz = 1;
  280.           fprintf (stderr, "time is in ticks, not seconds\n");
  281.         }
  282.     }
  283.     }
  284.   else
  285.     {
  286.       fprintf (stderr, "%s: don't know how to deal with file format %d\n",
  287.            whoami, file_format);
  288.       done (1);
  289.     }
  290.  
  291.   if (output_style & STYLE_GMON_INFO)
  292.     {
  293.       printf ("File `%s' (version %d) contains:\n",
  294.           filename, gmon_file_version);
  295.       printf ("\t%d histogram record%s\n",
  296.           nhist, nhist == 1 ? "" : "s");
  297.       printf ("\t%d call-graph record%s\n",
  298.           narcs, narcs == 1 ? "" : "s");
  299.       printf ("\t%d basic-block count record%s\n",
  300.           nbbs, nbbs == 1 ? "" : "s");
  301.       first_output = FALSE;
  302.     }
  303. }
  304.  
  305.  
  306. void
  307. DEFUN (gmon_out_write, (filename), const char *filename)
  308. {
  309.   FILE *ofp;
  310.   struct gmon_hdr ghdr;
  311.  
  312.   ofp = fopen (filename, FOPEN_WB);
  313.   if (!ofp)
  314.     {
  315.       perror (filename);
  316.       done (1);
  317.     }
  318.  
  319.   if (file_format == FF_AUTO || file_format == FF_MAGIC)
  320.     {
  321.       /* write gmon header: */
  322.  
  323.       memcpy (&ghdr.cookie[0], GMON_MAGIC, 4);
  324.       bfd_put_32 (core_bfd, GMON_VERSION, (bfd_byte *) ghdr.version);
  325.       if (fwrite (&ghdr, sizeof (ghdr), 1, ofp) != 1)
  326.     {
  327.       perror (filename);
  328.       done (1);
  329.     }
  330.  
  331.       /* write execution time histogram if we have one: */
  332.       if (gmon_input & INPUT_HISTOGRAM)
  333.     {
  334.       hist_write_hist (ofp, filename);
  335.     }
  336.  
  337.       /* write call graph arcs if we have any: */
  338.       if (gmon_input & INPUT_CALL_GRAPH)
  339.     {
  340.       cg_write_arcs (ofp, filename);
  341.     }
  342.  
  343.       /* write basic-block info if we have it: */
  344.       if (gmon_input & INPUT_BB_COUNTS)
  345.     {
  346.       bb_write_blocks (ofp, filename);
  347.     }
  348.     }
  349.   else if (file_format == FF_BSD)
  350.     {
  351.       struct raw_arc raw_arc;
  352.       UNIT raw_bin_count;
  353.       bfd_vma lpc, hpc;
  354.       int i, ncnt;
  355.       Arc *arc;
  356.       Sym *sym;
  357.  
  358.       put_vma (core_bfd, s_lowpc, (bfd_byte *) & lpc);
  359.       put_vma (core_bfd, s_highpc, (bfd_byte *) & hpc);
  360.       bfd_put_32 (core_bfd,
  361.           hist_num_bins * sizeof (UNIT) + sizeof (struct raw_phdr),
  362.             (bfd_byte *) & ncnt);
  363.  
  364.       /* write header: */
  365.       if (fwrite (&lpc, sizeof (lpc), 1, ofp) != 1
  366.       || fwrite (&hpc, sizeof (hpc), 1, ofp) != 1
  367.       || fwrite (&ncnt, sizeof (ncnt), 1, ofp) != 1)
  368.     {
  369.       perror (filename);
  370.       done (1);
  371.     }
  372.  
  373.       /* dump the samples: */
  374.  
  375.       for (i = 0; i < hist_num_bins; ++i)
  376.     {
  377.       bfd_put_16 (core_bfd, hist_sample[i], (bfd_byte *) & raw_bin_count[0]);
  378.       if (fwrite (&raw_bin_count[0], sizeof (raw_bin_count), 1, ofp) != 1)
  379.         {
  380.           perror (filename);
  381.           done (1);
  382.         }
  383.     }
  384.  
  385.       /* dump the normalized raw arc information: */
  386.  
  387.       for (sym = symtab.base; sym < symtab.limit; ++sym)
  388.     {
  389.       for (arc = sym->cg.children; arc; arc = arc->next_child)
  390.         {
  391.           put_vma (core_bfd, arc->parent->addr,
  392.                (bfd_byte *) raw_arc.from_pc);
  393.           put_vma (core_bfd, arc->child->addr,
  394.                (bfd_byte *) raw_arc.self_pc);
  395.           bfd_put_32 (core_bfd, arc->count, (bfd_byte *) raw_arc.count);
  396.           if (fwrite (&raw_arc, sizeof (raw_arc), 1, ofp) != 1)
  397.         {
  398.           perror (filename);
  399.           done (1);
  400.         }
  401.           DBG (SAMPLEDEBUG,
  402.            printf ("[dumpsum] frompc 0x%lx selfpc 0x%lx count %d\n",
  403.                arc->parent->addr, arc->child->addr, arc->count));
  404.         }
  405.     }
  406.       fclose (ofp);
  407.     }
  408.   else
  409.     {
  410.       fprintf (stderr, "%s: don't know how to deal with file format %d\n",
  411.            whoami, file_format);
  412.       done (1);
  413.     }
  414. }
  415.